home *** CD-ROM | disk | FTP | other *** search
- /* $Id: pl-pro.c,v 1.40 1998/04/15 15:17:07 jan Exp $
-
- Copyright (c) 1990 Jan Wielemaker. All rights reserved.
- See ../LICENCE to find out about your rights.
- jan@swi.psy.uva.nl
-
- Purpose: Support for virtual machine
- */
-
- #ifdef SECURE_GC
- #define O_SECURE 1 /* include checkData() */
- #endif
- #include "pl-incl.h"
- #ifdef HAVE_MALLOC_H
- #include <malloc.h>
- #endif
-
- /********************************
- * CALLING THE INTERPRETER *
- *********************************/
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Starts a new Prolog toplevel. Resets I/O to point to the user and stops
- the debugger. Restores I/O and debugger on exit. The Prolog predicate
- `$break' is called to actually built the break environment.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- word
- pl_break()
- { fid_t cid = PL_open_foreign_frame();
- term_t goal = PL_new_term_ref();
- word rval;
-
- PL_put_atom_chars(goal, "$break");
- rval = pl_break1(goal);
- PL_discard_foreign_frame(cid);
-
- return rval;
- }
-
-
- word
- pl_break1(term_t goal)
- { extern int Input, Output;
- bool rval;
-
- int inSave = Input;
- int outSave = Output;
- long skipSave = debugstatus.skiplevel;
- int suspSave = debugstatus.suspendTrace;
- int traceSave, debugSave;
-
- tracemode(FALSE, &traceSave);
- debugmode(FALSE, &debugSave);
-
- Input = 0;
- Output = 1;
-
- resetTracer();
-
- { fid_t cid = PL_open_foreign_frame();
-
- rval = callProlog(MODULE_user, goal, FALSE);
-
- PL_discard_foreign_frame(cid);
- }
-
- debugstatus.suspendTrace = suspSave;
- debugstatus.skiplevel = skipSave;
- tracemode(traceSave, NULL);
- debugmode(debugSave, NULL);
-
- Output = outSave;
- Input = inSave;
-
- return rval;
- }
-
-
- word
- pl_notrace1(term_t goal)
- { bool rval;
-
- long skipSave = debugstatus.skiplevel;
- bool traceSave = debugstatus.tracing;
-
- rval = callProlog(NULL, goal, FALSE);
-
- debugstatus.skiplevel = skipSave;
- debugstatus.tracing = traceSave;
-
- return rval;
- }
-
-
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Call a prolog goal from C. The argument must be an instantiated term
- like for the Prolog predicate call/1.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- int
- callProlog(Module module, term_t goal, int debug)
- { term_t g = PL_new_term_ref();
- functor_t fd;
- Procedure proc;
- int flags = (debug ? PL_Q_NORMAL : PL_Q_NODEBUG);
-
- PL_strip_module(goal, &module, g);
- if ( !PL_get_functor(g, &fd) )
- return warning("callProlog(): Illegal goal");
-
- proc = lookupProcedure(fd, module);
-
- { int arity = arityFunctor(fd);
- term_t args = PL_new_term_refs(arity);
- qid_t qid;
- int n, rval;
-
- for(n=0; n<arity; n++)
- PL_get_arg(n+1, g, args+n);
-
- qid = PL_open_query(module, flags, proc, args);
- rval = PL_next_solution(qid);
- PL_cut_query(qid);
-
- return rval;
- }
- }
-
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Bring the Prolog system itself to life. Prolog saves the C-stack to
- enable aborts. pl_abort() will close open files, reset all clause
- references to `0' and finally long_jumps back to prolog().
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- static jmp_buf abort_context; /* jmp buffer for abort() */
- static int can_abort; /* embeded code can't abort */
-
- word
- pl_abort()
- { if ( !can_abort )
- { warning("Embedded system, cannot abort");
- Halt(1);
- }
-
- if ( GD->critical > 0 ) /* abort in critical region: delay */
- { pl_notrace();
- LD->aborted = TRUE;
- succeed;
- }
-
- if ( !trueFeature(READLINE_FEATURE) )
- PopTty(&ttytab);
- LD->outofstack = FALSE;
- resetRead();
- closeFiles(FALSE);
- resetReferences();
- #ifdef O_PROFILE
- pl_reset_profiler();
- #endif
- resetStacks();
- resetTracer();
- resetSignals();
- resetForeign();
-
- longjmp(abort_context, 1);
- /*NOTREACHED*/
- fail;
- }
-
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Initial entry point from C to start the Prolog engine. Saves abort
- context, clears the stack and finally starts the virtual machine
- interpreter with the toplevel goal.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- bool
- prolog(volatile atom_t goal)
- { bool rval;
-
- if ( setjmp(abort_context) != 0 )
- { goal = ATOM_abort;
- } else
- { debugstatus.debugging = FALSE;
- }
-
- emptyStacks();
-
- #ifdef O_LIMIT_DEPTH
- depth_limit = (unsigned long)DEPTH_NO_LIMIT;
- #endif
-
- gc_status.blocked = 0;
- gc_status.requested = FALSE;
- #if O_SHIFT_STACKS
- shift_status.blocked = 0;
- #endif
- LD->in_arithmetic = 0;
-
- tracemode(FALSE, NULL);
- debugmode(FALSE, NULL);
- debugstatus.suspendTrace = 0;
-
- can_abort = TRUE;
- { fid_t fid = PL_open_foreign_frame();
- Procedure p = lookupProcedure(lookupFunctorDef(goal, 0), MODULE_system);
-
- for(;;)
- { qid_t qid;
- term_t except;
-
- *valTermRef(exception_printed) = 0;
- qid = PL_open_query(MODULE_system, PL_Q_NORMAL, p, 0);
- rval = PL_next_solution(qid);
- if ( !rval && (except = PL_exception(qid)) )
- { Word p1 = valTermRef(exception_printed);
- Word p2 = valTermRef(except);
- predicate_t pred = PL_predicate("unhandled_exception", 2, "$toplevel");
-
- deRef(p1);
- deRef(p2);
-
- { fid_t fid2 = PL_open_foreign_frame();
- term_t t0 = PL_new_term_refs(2);
-
- PL_put_atom(t0, *p1 == *p2 ? ATOM_true : ATOM_false);
- PL_put_term(t0+1, except);
-
- PL_call_predicate(NULL, FALSE, pred, t0);
- PL_close_foreign_frame(fid2);
- pl_notrace();
- }
- PL_close_query(qid);
- continue;
- }
- PL_close_query(qid);
- break;
- }
- PL_discard_foreign_frame(fid);
- }
- can_abort = FALSE;
-
- return rval;
- }
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Cut (!) as called via the meta-call mechanism has no effect.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- word
- pl_metacut(void)
- { succeed;
- }
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Just for debugging now and then.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- int
- trap_gdb()
- { return 0;
- }
-
- #if O_SECURE || O_DEBUG || defined(O_MAINTENANCE)
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- checkData(p) verifies p points to valid Prolog data and generates a
- system error otherwise. The checks performed are much more rigid than
- those during normal execution. Arity of terms is limited to 100 as a
- kind of heuristic.
-
- Note that we expect terms on the global stack. This is true in the
- interpreter, but not everywere in the system (records use terms on the
- heap).
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- #define onGlobal(p) onStack(global, p)
- #define onLocal(p) onStack(local, p)
- #define onHeap(p) ((char *)p >= (char *)hBase && (char *)p <= (char *)hTop)
-
- static void
- printk(char *fm, ...)
- { va_list args;
-
- va_start(args, fm);
- Sfprintf(Serror, "[DATA INCONSISTENCY: ");
- Svfprintf(Serror, fm, args);
- Sfprintf(Serror, "]\n");
- va_end(args);
-
- trap_gdb();
- }
-
-
- word
- checkData(Word p)
- { int arity; int n;
- Word p2;
-
- while(isRef(*p))
- { p2 = unRef(*p);
- if ( p2 > p )
- printk("Reference to higher address");
- if ( !onLocal(p2) && !onGlobal(p2) )
- printk("Illegal reference pointer at 0x%x --> 0x%x", p, p2);
-
- return checkData(p2);
- }
-
- if ( isVar(*p) )
- return 0x737473; /* just a random number */
-
- if ( isTaggedInt(*p) )
- return *p;
-
- if ( isIndirect(*p) )
- { if ( storage(*p) != STG_GLOBAL )
- printk("Indirect data not on global");
- if ( isBignum(*p) )
- return (word) valBignum(*p);
- if ( isReal(*p) )
- return (word) valReal(*p);
- if ( isString(*p) )
- { if ( sizeString(*p) != strlen(valString(*p)) )
- printk("String has inconsistent length: 0x%x", *p);
- return *addressIndirect(*p);
- }
- printk("Illegal indirect datatype");
- }
-
- if ( isAtom(*p) )
- return *p;
- /* now it should be a term */
- if ( tag(*p) != TAG_COMPOUND ||
- storage(*p) != STG_GLOBAL )
- printk("Illegal term at: %p: 0x%x", p, *p);
-
- { word key = 0L;
- Functor f = valueTerm(*p);
-
- if ( !onGlobal(f) )
- printk("Term at %p not on global stack", f);
-
- if ( tag(f->definition) != TAG_ATOM ||
- storage(f->definition) != STG_GLOBAL )
- printk("Illegal term: 0x%x", *p);
- arity = arityFunctor(f->definition);
- if (arity <= 0 || arity > 100)
- printk("Illegal arity");
- for(n=0; n<arity; n++)
- key += checkData(&f->arguments[n]);
-
- return key;
- }
- }
- #endif /* TEST */
-